using System.Collections.Generic;
using System.Linq;
using Godot;

namespace Arcane.Source.UI
{
    [GlobalClass]
    public partial class PagedGridContainer : Container
    {
        private readonly Stack<Control> _pool = new();
        private int _maxRow;
        private float _cellSize;
        private int _currentPage = 0;
        private int _col;
        [Export] int Column
        {
            get => _col;
            set
            {
                _col = value;
            }
        }

        public int PageCapacity => _adapter == null ? 0 : _maxRow * _col;
        public int CurrentPage
        {
            get => _currentPage;
            set
            {
                if (_currentPage != value)
                {
                    _currentPage = value;
                    RefreshPage();
                }
            }
        }
        public int PageCount => _adapter is IAdapter adapter ? Mathf.CeilToInt((double)adapter.GetCount() / PageCapacity) : 0;

        private IAdapter _adapter;

        public override void _Notification(int what)
        {
            if (what == NotificationReady || what == NotificationResized)
            {
                OnResize();
                RefreshPage();
            }
        }

        public void OnResize()
        {
            var (width, height) = GetRect().Size;
            _cellSize = width / _col;
            _maxRow = Mathf.FloorToInt(height / _cellSize);

            foreach(var child in GetChildren()[PageCapacity..].Cast<Control>())
            {
                _pool.Push(child);
                RemoveChild(child);
            }
        }

        public void SetAdapter(IAdapter adapter)
        {
            _adapter = adapter;
            foreach (var child in GetChildren()) child.QueueFree();
            while (_pool.Count > 0) _pool.Pop().QueueFree();
            RefreshPage();
        }

        public void NextPage()
        {
            if (CurrentPage < PageCount - 1) CurrentPage += 1;
        }

        public void PrevPage()
        {
            if (CurrentPage > 0) CurrentPage -= 1;
        }


        public void RefreshPage()
        {
            if (_adapter == null) return;

            ClearElements();

            var count = _adapter.GetCount();
            var capacity = PageCapacity;
            var start = capacity * _currentPage;
            for (int i = 0; i < capacity; i++)
            {
                var index = start + i;
                if (index >= count) break;
                
                var element = _pool.Count > 0 ? _pool.Pop() : _adapter.CreateElement();
                _adapter.BindElement(element, index);
                AddChild(element);
            }

            FitElements();
        }

        private void ClearElements(object _ = null)
        {
            foreach (var child in GetChildren().Cast<Control>())
            {
                _pool.Push(child);
                RemoveChild(child);
            }
        }

        private void FitElements(object _ = null)
        {
            var size = new Vector2(_cellSize, _cellSize);
            int pageIndex = 0;
            foreach (var child in GetChildren().Cast<Control>())
            {
                var col = pageIndex % _col;
                var row = pageIndex / _col;

                FitChildInRect(child, new(col * _cellSize, row * _cellSize, size));

                pageIndex += 1;
            }
        }
    }
}